import sys
import os
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QPushButton, QFileDialog, QListWidget,
                             QListWidgetItem, QComboBox, QSlider, QSpinBox, QTextEdit,
                             QMessageBox, QProgressBar, QLineEdit, QGroupBox, QGridLayout)
from PyQt5.QtGui import QPixmap, QImage, QPainter, QColor, QFont
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QUrl, QTimer
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PIL import Image, ImageFilter, ImageEnhance, ImageQt


class ShapeDetectionThread(QThread):
    """形状检测线程"""
    detection_complete = pyqtSignal(object)
    progress_updated = pyqtSignal(int)

    def __init__(self, image, shape_types, min_area, max_area):
        super().__init__()
        self.image = image
        self.shape_types = shape_types
        self.min_area = min_area
        self.max_area = max_area

    def run(self):
        try:
            # 转换为OpenCV格式
            img_cv = cv2.cvtColor(np.array(self.image), cv2.COLOR_RGB2BGR)
            img_gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)

            # 进度更新
            self.progress_updated.emit(20)

            # 高斯模糊和边缘检测
            blur = cv2.GaussianBlur(img_gray, (5, 5), 0)
            _, thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

            # 进度更新
            self.progress_updated.emit(40)

            # 查找轮廓
            contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # 进度更新
            self.progress_updated.emit(60)

            # 分析轮廓
            detected_shapes = []
            for contour in contours:
                area = cv2.contourArea(contour)

                # 过滤面积
                if area < self.min_area or area > self.max_area:
                    continue

                # 计算轮廓周长和近似多边形
                perimeter = cv2.arcLength(contour, True)
                approx = cv2.approxPolyDP(contour, 0.04 * perimeter, True)
                x, y, w, h = cv2.boundingRect(approx)

                # 形状分类
                shape_type = None
                if "圆形" in self.shape_types:
                    # 圆形检测
                    (cx, cy), radius = cv2.minEnclosingCircle(contour)
                    circle_area = np.pi * radius * radius
                    if abs(area - circle_area) / circle_area < 0.2:
                        shape_type = "圆形"
                        detected_shapes.append({
                            'type': shape_type,
                            'contour': contour,
                            'center': (int(cx), int(cy)),
                            'radius': int(radius),
                            'area': area
                        })
                        continue

                if len(approx) == 3 and "三角形" in self.shape_types:
                    shape_type = "三角形"
                elif len(approx) == 4 and "矩形" in self.shape_types:
                    shape_type = "矩形"
                elif len(approx) > 4 and "多边形" in self.shape_types:
                    shape_type = "多边形"

                if shape_type:
                    detected_shapes.append({
                        'type': shape_type,
                        'contour': contour,
                        'vertices': approx,
                        'area': area
                    })

            # 进度更新
            self.progress_updated.emit(100)

            # 返回结果
            self.detection_complete.emit({
                'original_image': self.image,
                'detected_shapes': detected_shapes
            })

        except Exception as e:
            self.detection_complete.emit(None)


class PanoramaStitchingThread(QThread):
    """图像拼接线程"""
    stitching_complete = pyqtSignal(object)
    progress_updated = pyqtSignal(int)

    def __init__(self, images, stitching_method):
        super().__init__()
        self.images = images
        self.stitching_method = stitching_method

    def run(self):
        try:
            if not self.images or len(self.images) < 2:
                self.stitching_complete.emit(None)
                return

            # 转换为OpenCV格式
            cv_images = [cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) for img in self.images]

            # 进度更新
            self.progress_updated.emit(10)

            # 图像拼接
            if self.stitching_method == "自动":
                stitcher = cv2.Stitcher.create(cv2.Stitcher_SCANS) if cv2.__version__.startswith(
                    '4') else cv2.createStitcher(cv2.Stitcher_SCANS)
            else:
                stitcher = cv2.Stitcher.create(cv2.Stitcher_PANORAMA) if cv2.__version__.startswith(
                    '4') else cv2.createStitcher(cv2.Stitcher_PANORAMA)

            # 进度更新
            self.progress_updated.emit(30)

            # 执行拼接
            status, result = stitcher.stitch(cv_images)

            # 进度更新
            self.progress_updated.emit(80)

            if status == cv2.Stitcher_OK:
                # 转换回PIL格式
                result_pil = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))

                # 进度更新
                self.progress_updated.emit(100)

                self.stitching_complete.emit(result_pil)
            else:
                self.stitching_complete.emit(None)

        except Exception as e:
            self.stitching_complete.emit(None)


class VideoPlayer(QWidget):
    """视频播放器组件"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent
        self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.video_widget = QVideoWidget()

        # 播放控制按钮
        self.play_btn = QPushButton("播放")
        self.pause_btn = QPushButton("暂停")
        self.stop_btn = QPushButton("停止")
        self.fast_forward_btn = QPushButton("快进")
        self.fast_backward_btn = QPushButton("快退")

        # 音量控制
        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(70)
        self.volume_slider.valueChanged.connect(self.set_volume)

        # 进度条
        self.progress_bar = QSlider(Qt.Horizontal)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_progress)

        # 时间显示
        self.time_label = QLabel("00:00/00:00")

        # 布局
        controls_layout = QHBoxLayout()
        controls_layout.addWidget(self.play_btn)
        controls_layout.addWidget(self.pause_btn)
        controls_layout.addWidget(self.stop_btn)
        controls_layout.addWidget(self.fast_backward_btn)
        controls_layout.addWidget(self.fast_forward_btn)
        controls_layout.addWidget(QLabel("音量:"))
        controls_layout.addWidget(self.volume_slider)

        progress_layout = QHBoxLayout()
        progress_layout.addWidget(self.progress_bar)
        progress_layout.addWidget(self.time_label)

        main_layout = QVBoxLayout(self)
        main_layout.addWidget(self.video_widget)
        main_layout.addLayout(controls_layout)
        main_layout.addLayout(progress_layout)

        # 信号连接
        self.play_btn.clicked.connect(self.media_player.play)
        self.pause_btn.clicked.connect(self.media_player.pause)
        self.stop_btn.clicked.connect(self.stop_video)
        self.fast_forward_btn.clicked.connect(lambda: self.seek(+10))  # 快进10秒
        self.fast_backward_btn.clicked.connect(lambda: self.seek(-10))  # 快退10秒
        self.progress_bar.sliderMoved.connect(lambda position: self.media_player.setPosition(position))
        self.media_player.positionChanged.connect(self.update_progress_bar)
        self.media_player.durationChanged.connect(self.set_progress_bar_range)
        self.media_player.stateChanged.connect(self.update_play_button_state)

        # 初始设置
        self.media_player.setVideoOutput(self.video_widget)
        self.set_volume(70)

    def open_video(self, file_path):
        """打开本地视频文件"""
        self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(file_path)))
        self.timer.start(50)  # 每秒更新20次进度
        self.media_player.play()

    def stop_video(self):
        """停止播放"""
        self.media_player.stop()
        self.progress_bar.setValue(0)

    def seek(self, seconds):
        """快进/快退指定秒数"""
        current_pos = self.media_player.position()
        new_pos = current_pos + seconds * 1000  # 转换为毫秒
        self.media_player.setPosition(new_pos)

    def set_volume(self, value):
        """设置音量"""
        self.media_player.setVolume(value)

    def update_progress(self):
        """更新播放进度"""
        if self.media_player.state() == QMediaPlayer.PlayingState:
            self.progress_bar.setValue(self.media_player.position())
            self.update_time_display()

    def update_progress_bar(self, position):
        """同步进度条位置"""
        self.progress_bar.setValue(position)
        self.update_time_display()

    def set_progress_bar_range(self, duration):
        """设置进度条范围"""
        self.progress_bar.setRange(0, duration)
        self.update_time_display()

    def update_time_display(self):
        """更新时间显示"""
        current_position = self.media_player.position()
        duration = self.media_player.duration()

        if duration > 0:
            current_time = self.format_time(current_position)
            total_time = self.format_time(duration)
            self.time_label.setText(f"{current_time}/{total_time}")

    def format_time(self, ms):
        """将毫秒转换为MM:SS格式"""
        seconds = int(ms / 1000)
        minutes = seconds // 60
        seconds %= 60
        return f"{minutes:02d}:{seconds:02d}"

    def update_play_button_state(self, state):
        """更新播放按钮状态"""
        if state == QMediaPlayer.PlayingState:
            self.play_btn.setText("播放")
        else:
            self.play_btn.setText("暂停")


class ImageProcessor(QMainWindow):
    def __init__(self):
        super().__init__()

        self.current_image = None
        self.original_image = None
        self.current_image_path = None
        self.detected_shapes = None
        self.shape_detection_thread = None
        self.stitching_thread = None
        self.images_to_stitch = []

        # 设置中文字体
        font = QFont()
        font.setFamily("SimHei")
        self.setFont(font)

        self.init_ui()

    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("图像处理与视频播放平台")
        self.setGeometry(100, 100, 1200, 800)

        # 创建主布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)

        # 左侧面板 - 文件浏览器
        left_panel = QTabWidget()
        left_panel.setMaximumWidth(300)

        # 文件浏览器
        self.file_browser_widget = QWidget()
        file_browser_layout = QVBoxLayout(self.file_browser_widget)

        self.file_list = QListWidget()
        self.file_list.itemDoubleClicked.connect(self.load_local_image)

        file_buttons_layout = QHBoxLayout()
        self.open_folder_btn = QPushButton("打开文件夹")
        self.open_folder_btn.clicked.connect(self.open_folder)
        file_buttons_layout.addWidget(self.open_folder_btn)

        file_browser_layout.addLayout(file_buttons_layout)
        file_browser_layout.addWidget(self.file_list)

        left_panel.addTab(self.file_browser_widget, "本地文件")

        # 中央面板 - 显示图像
        self.image_display = QLabel("请打开或选择一张图片")
        self.image_display.setAlignment(Qt.AlignCenter)
        self.image_display.setMinimumSize(400, 400)
        self.image_display.setStyleSheet("border: 1px solid #cccccc;")

        # 右侧面板 - 包含图像处理工具
        self.tools_panel = QTabWidget()

        # 基本操作工具
        self.basic_tools = QWidget()
        basic_tools_layout = QVBoxLayout(self.basic_tools)

        # 调整大小
        resize_group = QGroupBox("调整大小")
        resize_layout = QGridLayout(resize_group)

        resize_layout.addWidget(QLabel("宽度:"), 0, 0)
        self.resize_width = QSpinBox()
        self.resize_width.setRange(1, 10000)
        self.resize_width.setValue(800)
        resize_layout.addWidget(self.resize_width, 0, 1)

        resize_layout.addWidget(QLabel("高度:"), 1, 0)
        self.resize_height = QSpinBox()
        self.resize_height.setRange(1, 10000)
        self.resize_height.setValue(600)
        resize_layout.addWidget(self.resize_height, 1, 1)

        self.resize_btn = QPushButton("调整大小")
        self.resize_btn.clicked.connect(self.resize_image)
        resize_layout.addWidget(self.resize_btn, 2, 0, 1, 2)

        # 旋转
        rotate_group = QGroupBox("旋转")
        rotate_layout = QGridLayout(rotate_group)

        self.rotate_angle = QComboBox()
        self.rotate_angle.addItems(["90", "180", "270", "自定义"])
        rotate_layout.addWidget(self.rotate_angle, 0, 0)

        self.rotate_custom = QSpinBox()
        self.rotate_custom.setRange(1, 359)
        self.rotate_custom.setValue(45)
        self.rotate_custom.setEnabled(False)
        rotate_layout.addWidget(self.rotate_custom, 0, 1)

        self.rotate_angle.currentIndexChanged.connect(self.toggle_custom_rotate)

        self.rotate_btn = QPushButton("旋转")
        self.rotate_btn.clicked.connect(self.rotate_image)
        rotate_layout.addWidget(self.rotate_btn, 1, 0, 1, 2)

        # 翻转
        flip_group = QGroupBox("翻转")
        flip_layout = QHBoxLayout(flip_group)

        self.flip_horizontal_btn = QPushButton("水平翻转")
        self.flip_horizontal_btn.clicked.connect(lambda: self.flip_image(Image.FLIP_LEFT_RIGHT))
        flip_layout.addWidget(self.flip_horizontal_btn)

        self.flip_vertical_btn = QPushButton("垂直翻转")
        self.flip_vertical_btn.clicked.connect(lambda: self.flip_image(Image.FLIP_TOP_BOTTOM))
        flip_layout.addWidget(self.flip_vertical_btn)

        # 保存
        save_group = QGroupBox("保存")
        save_layout = QHBoxLayout(save_group)

        self.save_btn = QPushButton("保存")
        self.save_btn.clicked.connect(self.save_image)
        save_layout.addWidget(self.save_btn)

        self.save_as_btn = QPushButton("另存为")
        self.save_as_btn.clicked.connect(self.save_image_as)
        save_layout.addWidget(self.save_as_btn)

        basic_tools_layout.addWidget(resize_group)
        basic_tools_layout.addWidget(rotate_group)
        basic_tools_layout.addWidget(flip_group)
        basic_tools_layout.addWidget(save_group)
        basic_tools_layout.addStretch()

        # 滤镜工具
        self.filter_tools = QWidget()
        filter_tools_layout = QVBoxLayout(self.filter_tools)

        # 滤镜选择
        filter_group = QGroupBox("滤镜")
        filter_layout = QVBoxLayout(filter_group)

        self.filter_list = QComboBox()
        self.filter_list.addItems([
            "模糊", "锐化", "边缘检测", "浮雕", "轮廓", "平滑", "细节增强"
        ])
        filter_layout.addWidget(self.filter_list)

        self.apply_filter_btn = QPushButton("应用滤镜")
        self.apply_filter_btn.clicked.connect(self.apply_filter)
        filter_layout.addWidget(self.apply_filter_btn)

        # 图像增强
        enhance_group = QGroupBox("图像增强")
        enhance_layout = QGridLayout(enhance_group)

        enhance_layout.addWidget(QLabel("亮度:"), 0, 0)
        self.brightness_slider = QSlider(Qt.Horizontal)
        self.brightness_slider.setRange(0, 200)
        self.brightness_slider.setValue(100)
        enhance_layout.addWidget(self.brightness_slider, 0, 1)

        enhance_layout.addWidget(QLabel("对比度:"), 1, 0)
        self.contrast_slider = QSlider(Qt.Horizontal)
        self.contrast_slider.setRange(0, 200)
        self.contrast_slider.setValue(100)
        enhance_layout.addWidget(self.contrast_slider, 1, 1)

        enhance_layout.addWidget(QLabel("饱和度:"), 2, 0)
        self.saturation_slider = QSlider(Qt.Horizontal)
        self.saturation_slider.setRange(0, 200)
        self.saturation_slider.setValue(100)
        enhance_layout.addWidget(self.saturation_slider, 2, 1)

        enhance_layout.addWidget(QLabel("锐度:"), 3, 0)
        self.sharpness_slider = QSlider(Qt.Horizontal)
        self.sharpness_slider.setRange(0, 200)
        self.sharpness_slider.setValue(100)
        enhance_layout.addWidget(self.sharpness_slider, 3, 1)

        self.enhance_btn = QPushButton("应用增强")
        self.enhance_btn.clicked.connect(self.enhance_image)
        enhance_layout.addWidget(self.enhance_btn, 4, 0, 1, 2)

        filter_tools_layout.addWidget(filter_group)
        filter_tools_layout.addWidget(enhance_group)
        filter_tools_layout.addStretch()

        # 裁剪工具
        self.crop_tools = QWidget()
        crop_tools_layout = QVBoxLayout(self.crop_tools)

        # 裁剪区域输入
        crop_group = QGroupBox("裁剪图像")
        crop_layout = QGridLayout(crop_group)

        crop_layout.addWidget(QLabel("左边界 (X):"), 0, 0)
        self.crop_x = QSpinBox()
        self.crop_x.setRange(0, 10000)
        crop_layout.addWidget(self.crop_x, 0, 1)

        crop_layout.addWidget(QLabel("上边界 (Y):"), 1, 0)
        self.crop_y = QSpinBox()
        self.crop_y.setRange(0, 10000)
        crop_layout.addWidget(self.crop_y, 1, 1)

        crop_layout.addWidget(QLabel("宽度:"), 2, 0)
        self.crop_width = QSpinBox()
        self.crop_width.setRange(1, 10000)
        crop_layout.addWidget(self.crop_width, 2, 1)

        crop_layout.addWidget(QLabel("高度:"), 3, 0)
        self.crop_height = QSpinBox()
        self.crop_height.setRange(1, 10000)
        crop_layout.addWidget(self.crop_height, 3, 1)

        self.crop_btn = QPushButton("应用裁剪")
        self.crop_btn.clicked.connect(self.crop_image)
        crop_layout.addWidget(self.crop_btn, 4, 0, 1, 2)

        crop_tools_layout.addWidget(crop_group)
        crop_tools_layout.addStretch()

        # 平滑处理工具
        self.smooth_tools = QWidget()
        smooth_tools_layout = QVBoxLayout(self.smooth_tools)

        # 平滑算法选择
        smooth_group = QGroupBox("平滑处理")
        smooth_layout = QVBoxLayout(smooth_group)

        self.smooth_algorithm = QComboBox()
        self.smooth_algorithm.addItems([
            "均值滤波", "高斯模糊", "中值滤波", "双边滤波"
        ])
        smooth_layout.addWidget(self.smooth_algorithm)

        # 平滑强度控制
        smooth_strength_layout = QHBoxLayout()
        smooth_strength_layout.addWidget(QLabel("强度:"))
        self.smooth_strength = QSlider(Qt.Horizontal)
        self.smooth_strength.setRange(1, 10)
        self.smooth_strength.setValue(3)
        smooth_strength_layout.addWidget(self.smooth_strength)
        smooth_layout.addLayout(smooth_strength_layout)

        self.smooth_btn = QPushButton("应用平滑")
        self.smooth_btn.clicked.connect(self.apply_smoothing)
        smooth_layout.addWidget(self.smooth_btn)

        smooth_tools_layout.addWidget(smooth_group)
        smooth_tools_layout.addStretch()

        # 形状识别工具
        self.shape_detection_tools = QWidget()
        shape_detection_layout = QVBoxLayout(self.shape_detection_tools)

        # 形状类型选择
        shape_type_group = QGroupBox("形状类型")
        shape_type_layout = QVBoxLayout(shape_type_group)

        self.shape_types = {
            "圆形": QPushButton("圆形"),
            "矩形": QPushButton("矩形"),
            "三角形": QPushButton("三角形"),
            "多边形": QPushButton("多边形")
        }

        for shape, btn in self.shape_types.items():
            btn.setCheckable(True)
            btn.setChecked(True)
            shape_type_layout.addWidget(btn)

        shape_detection_layout.addWidget(shape_type_group)

        # 面积过滤
        area_filter_group = QGroupBox("面积过滤")
        area_filter_layout = QGridLayout(area_filter_group)

        area_filter_layout.addWidget(QLabel("最小面积:"), 0, 0)
        self.min_area = QSpinBox()
        self.min_area.setRange(100, 100000)
        self.min_area.setValue(500)
        area_filter_layout.addWidget(self.min_area, 0, 1)

        area_filter_layout.addWidget(QLabel("最大面积:"), 1, 0)
        self.max_area = QSpinBox()
        self.max_area.setRange(100, 100000)
        self.max_area.setValue(100000)
        area_filter_layout.addWidget(self.max_area, 1, 1)

        shape_detection_layout.addWidget(area_filter_group)

        # 形状识别按钮
        self.detect_shapes_btn = QPushButton("检测形状")
        self.detect_shapes_btn.clicked.connect(self.detect_shapes)
        shape_detection_layout.addWidget(self.detect_shapes_btn)

        # 形状检测进度条
        self.shape_detection_progress = QProgressBar()
        self.shape_detection_progress.hide()
        shape_detection_layout.addWidget(self.shape_detection_progress)

        # 形状统计信息
        self.shape_stats = QTextEdit()
        self.shape_stats.setReadOnly(True)
        self.shape_stats.setPlaceholderText("形状统计信息将显示在这里")
        shape_detection_layout.addWidget(self.shape_stats)

        shape_detection_layout.addStretch()

        # 图像拼接工具
        self.stitching_tools = QWidget()
        stitching_layout = QVBoxLayout(self.stitching_tools)

        # 已选择的图像列表
        self.stitching_images_list = QListWidget()
        self.stitching_images_list.setSelectionMode(QListWidget.ExtendedSelection)
        stitching_layout.addWidget(self.stitching_images_list)

        # 添加/移除图像按钮
        buttons_layout = QHBoxLayout()
        self.add_to_stitching_btn = QPushButton("添加到拼接")
        self.add_to_stitching_btn.clicked.connect(self.add_to_stitching)
        buttons_layout.addWidget(self.add_to_stitching_btn)

        self.remove_from_stitching_btn = QPushButton("从拼接移除")
        self.remove_from_stitching_btn.clicked.connect(self.remove_from_stitching)
        buttons_layout.addWidget(self.remove_from_stitching_btn)

        stitching_layout.addLayout(buttons_layout)

        # 拼接方法选择
        method_group = QGroupBox("拼接方法")
        method_layout = QVBoxLayout(method_group)

        self.stitching_method = QComboBox()
        self.stitching_method.addItems(["自动", "全景"])
        method_layout.addWidget(self.stitching_method)

        stitching_layout.addWidget(method_group)

        # 拼接按钮
        self.stitch_images_btn = QPushButton("开始拼接")
        self.stitch_images_btn.clicked.connect(self.stitch_images)
        stitching_layout.addWidget(self.stitch_images_btn)

        # 拼接进度条
        self.stitching_progress = QProgressBar()
        self.stitching_progress.hide()
        stitching_layout.addWidget(self.stitching_progress)

        stitching_layout.addStretch()

        # 视频播放工具
        self.video_playback_tools = QWidget()
        video_layout = QVBoxLayout(self.video_playback_tools)

        # 视频文件选择
        self.open_video_btn = QPushButton("打开视频文件")
        self.open_video_btn.clicked.connect(self.open_video_file)
        video_layout.addWidget(self.open_video_btn)

        # 视频播放器组件
        self.video_player = VideoPlayer(self)
        video_layout.addWidget(self.video_player)

        # 添加到工具面板
        self.tools_panel.addTab(self.basic_tools, "基本操作")
        self.tools_panel.addTab(self.filter_tools, "滤镜与增强")
        self.tools_panel.addTab(self.crop_tools, "裁剪")
        self.tools_panel.addTab(self.smooth_tools, "平滑处理")
        self.tools_panel.addTab(self.shape_detection_tools, "形状识别")
        self.tools_panel.addTab(self.stitching_tools, "图像拼接")
        self.tools_panel.addTab(self.video_playback_tools, "视频播放")
        self.tools_panel.setMaximumWidth(300)

        # 添加所有面板到主布局
        main_layout.addWidget(left_panel)
        main_layout.addWidget(self.image_display, 1)
        main_layout.addWidget(self.tools_panel)

        # 状态栏
        self.statusBar().showMessage("就绪")

    def open_folder(self):
        """打开文件夹并显示其中的图像文件"""
        folder_path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if folder_path:
            self.current_folder = folder_path
            self.file_list.clear()
            image_extensions = ["jpg", "jpeg", "png", "bmp", "gif", "tiff"]
            video_extensions = ["mp4", "avi", "mkv", "flv"]
            for file_name in os.listdir(folder_path):
                if any(file_name.lower().endswith(ext) for ext in image_extensions + video_extensions):
                    item = QListWidgetItem(file_name)
                    # 根据文件类型设置图标或标记
                    if any(file_name.lower().endswith(ext) for ext in video_extensions):
                        item.setToolTip("视频文件")
                    else:
                        item.setToolTip("图像文件")
                    self.file_list.addItem(item)
            self.statusBar().showMessage(f"已加载文件夹: {folder_path}")

    def load_local_image(self, item):
        """加载本地图像文件"""
        file_name = item.text()
        file_path = os.path.join(self.current_folder, file_name)

        # 检查文件类型
        image_extensions = ["jpg", "jpeg", "png", "bmp", "gif", "tiff"]
        if any(file_name.lower().endswith(ext) for ext in image_extensions):
            self.current_image_path = file_path
            self.load_image(self.current_image_path)
        else:
            # 视频文件
            self.video_player.open_video(file_path)
            self.statusBar().showMessage(f"已加载视频: {file_name}")

    def load_image(self, image_path):
        """加载并显示图像"""
        try:
            self.original_image = Image.open(image_path).convert('RGB')
            self.current_image = self.original_image.copy()
            self.detected_shapes = None
            self.shape_stats.clear()

            # 自动填充裁剪输入框的最大尺寸
            img_width, img_height = self.current_image.size
            self.crop_x.setMaximum(img_width - 1)
            self.crop_y.setMaximum(img_height - 1)
            self.crop_width.setMaximum(img_width)
            self.crop_height.setMaximum(img_height)
            self.crop_width.setValue(img_width)  # 默认填充完整宽度
            self.crop_height.setValue(img_height)  # 默认填充完整高度

            self.update_image_display()
            self.statusBar().showMessage(f"已加载图像: {os.path.basename(image_path)}")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"无法加载图像: {str(e)}")
            self.statusBar().showMessage("加载图像失败")

    def update_image_display(self):
        """更新图像显示"""
        if self.current_image:
            # 如果有检测到的形状，在图像上绘制
            display_image = self.current_image.copy()
            if self.detected_shapes:
                display_image = self.draw_detected_shapes(display_image)

            # 将PIL图像转换为Qt图像
            qimage = ImageQt.ImageQt(display_image)
            pixmap = QPixmap.fromImage(qimage)

            # 调整图像大小以适应显示区域
            display_width = self.image_display.width()
            display_height = self.image_display.height()
            scaled_pixmap = pixmap.scaled(display_width, display_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)

            self.image_display.setPixmap(scaled_pixmap)

    def resizeEvent(self, event):
        """窗口大小改变时调整图像显示"""
        self.update_image_display()
        super().resizeEvent(event)

    def toggle_custom_rotate(self, index):
        """切换自定义旋转角度输入框的启用状态"""
        self.rotate_custom.setEnabled(index == 3)  # 最后一个选项是"自定义"

    def resize_image(self):
        """调整图像大小"""
        if self.current_image:
            width = self.resize_width.value()
            height = self.resize_height.value()
            self.current_image = self.current_image.resize((width, height), Image.LANCZOS)
            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage(f"已调整图像大小为 {width}x{height}")

    def rotate_image(self):
        """旋转图像"""
        if self.current_image:
            index = self.rotate_angle.currentIndex()
            if index == 3:  # 自定义角度
                angle = self.rotate_custom.value()
            else:
                angle = [90, 180, 270][index]

            self.current_image = self.current_image.rotate(angle, expand=True)
            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage(f"已旋转图像 {angle} 度")

    def flip_image(self, method):
        """翻转图像"""
        if self.current_image:
            self.current_image = self.current_image.transpose(method)
            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage("已翻转图像")

    def apply_filter(self):
        """应用滤镜"""
        if self.current_image:
            filter_name = self.filter_list.currentText()
            filters = {
                "模糊": ImageFilter.BLUR,
                "锐化": ImageFilter.SHARPEN,
                "边缘检测": ImageFilter.FIND_EDGES,
                "浮雕": ImageFilter.EMBOSS,
                "轮廓": ImageFilter.CONTOUR,
                "平滑": ImageFilter.SMOOTH,
                "细节增强": ImageFilter.DETAIL
            }

            if filter_name in filters:
                self.current_image = self.current_image.filter(filters[filter_name])
                self.detected_shapes = None
                self.shape_stats.clear()
                self.update_image_display()
                self.statusBar().showMessage(f"已应用滤镜: {filter_name}")

    def enhance_image(self):
        """增强图像"""
        if self.current_image:
            # 获取滑块值
            brightness = self.brightness_slider.value() / 100.0
            contrast = self.contrast_slider.value() / 100.0
            saturation = self.saturation_slider.value() / 100.0
            sharpness = self.sharpness_slider.value() / 100.0

            # 应用增强
            img = self.current_image

            if brightness != 1.0:
                enhancer = ImageEnhance.Brightness(img)
                img = enhancer.enhance(brightness)

            if contrast != 1.0:
                enhancer = ImageEnhance.Contrast(img)
                img = enhancer.enhance(contrast)

            if saturation != 1.0:
                enhancer = ImageEnhance.Color(img)
                img = enhancer.enhance(saturation)

            if sharpness != 1.0:
                enhancer = ImageEnhance.Sharpness(img)
                img = enhancer.enhance(sharpness)

            self.current_image = img
            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage("已应用图像增强")

    def crop_image(self):
        """裁剪当前图像"""
        if not self.current_image:
            QMessageBox.warning(self, "警告", "请先加载图像")
            return

        # 获取裁剪参数
        x = self.crop_x.value()
        y = self.crop_y.value()
        width = self.crop_width.value()
        height = self.crop_height.value()

        # 验证参数有效性（不超过图像尺寸）
        img_width, img_height = self.current_image.size
        if x + width > img_width or y + height > img_height:
            QMessageBox.warning(self, "错误", "裁剪区域超出图像范围")
            return

        # 执行裁剪
        try:
            self.current_image = self.current_image.crop((x, y, x + width, y + height))
            self.detected_shapes = None
            self.shape_stats.clear()

            # 更新裁剪输入框的最大尺寸
            self.crop_x.setMaximum(img_width - 1)
            self.crop_y.setMaximum(img_height - 1)
            self.crop_width.setMaximum(width)
            self.crop_height.setMaximum(height)

            self.update_image_display()
            self.statusBar().showMessage(f"已裁剪图像（区域：{x},{y} 尺寸：{width}x{height}）")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"裁剪失败：{str(e)}")
            self.statusBar().showMessage("裁剪失败")

    def apply_smoothing(self):
        """应用平滑处理"""
        if not self.current_image:
            QMessageBox.warning(self, "警告", "请先加载图像")
            return

        algorithm = self.smooth_algorithm.currentText()
        strength = self.smooth_strength.value()

        try:
            if algorithm == "均值滤波":
                # 均值滤波使用盒式滤波器，size参数控制平滑程度
                size = 2 * strength + 1  # 确保为奇数
                self.current_image = self.current_image.filter(ImageFilter.BoxBlur(size))

            elif algorithm == "高斯模糊":
                # 高斯模糊，radius参数控制平滑程度
                self.current_image = self.current_image.filter(ImageFilter.GaussianBlur(radius=strength))

            elif algorithm == "中值滤波":
                # 中值滤波，对椒盐噪声效果较好
                # PIL的中值滤波只接受固定的size=3，这里通过多次应用来增强效果
                for _ in range(strength):
                    self.current_image = self.current_image.filter(ImageFilter.MedianFilter())

            elif algorithm == "双边滤波":
                # PIL没有直接的双边滤波实现，这里使用简单的高斯滤波作为替代
                # 真正的双边滤波需要保持边缘，这里无法完全实现
                self.current_image = self.current_image.filter(ImageFilter.GaussianBlur(radius=strength))

            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage(f"已应用{algorithm}（强度：{strength}）")

        except Exception as e:
            QMessageBox.critical(self, "错误", f"平滑处理失败：{str(e)}")
            self.statusBar().showMessage("平滑处理失败")

    def detect_shapes(self):
        """检测图像中的形状"""
        if not self.current_image:
            QMessageBox.warning(self, "警告", "请先加载图像")
            return

        # 获取用户选择的形状类型
        selected_shapes = [shape for shape, btn in self.shape_types.items() if btn.isChecked()]
        if not selected_shapes:
            QMessageBox.warning(self, "警告", "请至少选择一种形状类型")
            return

        # 获取面积过滤参数
        min_area = self.min_area.value()
        max_area = self.max_area.value()

        # 禁用按钮并显示进度条
        self.detect_shapes_btn.setEnabled(False)
        self.shape_detection_progress.show()
        self.shape_detection_progress.setValue(0)
        self.statusBar().showMessage("正在检测形状...")

        # 创建并启动形状检测线程
        self.shape_detection_thread = ShapeDetectionThread(
            self.current_image, selected_shapes, min_area, max_area
        )
        self.shape_detection_thread.detection_complete.connect(self.on_shape_detection_complete)
        self.shape_detection_thread.progress_updated.connect(self.shape_detection_progress.setValue)
        self.shape_detection_thread.start()

    def on_shape_detection_complete(self, result):
        """形状检测完成回调"""
        # 启用按钮并隐藏进度条
        self.detect_shapes_btn.setEnabled(True)
        self.shape_detection_progress.hide()

        if result:
            self.detected_shapes = result['detected_shapes']
            self.update_image_display()

            # 更新统计信息
            self.update_shape_statistics()

            self.statusBar().showMessage(f"形状检测完成，共检测到 {len(self.detected_shapes)} 个形状")
        else:
            QMessageBox.critical(self, "错误", "形状检测失败")
            self.statusBar().showMessage("形状检测失败")

    def update_shape_statistics(self):
        """更新形状统计信息"""
        if not self.detected_shapes:
            self.shape_stats.clear()
            return

        # 统计每种形状的数量
        shape_counts = {}
        for shape in self.detected_shapes:
            shape_type = shape['type']
            if shape_type in shape_counts:
                shape_counts[shape_type] += 1
            else:
                shape_counts[shape_type] = 1

        # 生成统计信息文本
        stats_text = "形状统计信息:\n\n"
        for shape_type, count in shape_counts.items():
            stats_text += f"{shape_type}: {count} 个\n"

        # 添加总面积信息
        total_area = sum(shape['area'] for shape in self.detected_shapes)
        stats_text += f"\n总面积: {total_area} 像素"

        self.shape_stats.setText(stats_text)

    def draw_detected_shapes(self, image):
        """在图像上绘制检测到的形状"""
        if not self.detected_shapes:
            return image

        # 创建绘图对象
        img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)

        # 定义每种形状的颜色
        colors = {
            "圆形": (0, 255, 0),  # 绿色
            "矩形": (255, 0, 0),  # 蓝色
            "三角形": (0, 0, 255),  # 红色
            "多边形": (255, 255, 0)  # 青色
        }

        # 绘制每个形状
        for shape in self.detected_shapes:
            shape_type = shape['type']
            color = colors.get(shape_type, (255, 255, 255))  # 默认白色

            if shape_type == "圆形":
                # 绘制圆形
                cv2.circle(img_cv, shape['center'], shape['radius'], color, 2)
                # 添加标签
                cv2.putText(img_cv, f"圆形",
                            (shape['center'][0] - shape['radius'], shape['center'][1] - shape['radius'] - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

            else:
                # 绘制多边形
                cv2.drawContours(img_cv, [shape['contour']], -1, color, 2)
                # 计算中心点
                M = cv2.moments(shape['contour'])
                if M["m00"] != 0:
                    cX = int(M["m10"] / M["m00"])
                    cY = int(M["m01"] / M["m00"])
                    # 添加标签
                    cv2.putText(img_cv, shape_type, (cX - 20, cY - 10),
                                cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

        # 转换回PIL图像
        return Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))

    def add_to_stitching(self):
        """将当前图像添加到拼接队列"""
        if not self.current_image:
            QMessageBox.warning(self, "警告", "请先加载图像")
            return

        if self.current_image_path:
            file_name = os.path.basename(self.current_image_path)
            # 检查是否已添加
            for i in range(self.stitching_images_list.count()):
                if self.stitching_images_list.item(i).text() == file_name:
                    QMessageBox.warning(self, "警告", "该图像已添加到拼接队列")
                    return

            # 添加到列表
            self.stitching_images_list.addItem(file_name)
            # 保存图像副本到拼接列表
            self.images_to_stitch.append(self.current_image.copy())
            self.statusBar().showMessage(f"已添加图像到拼接队列: {file_name}")
        else:
            QMessageBox.warning(self, "警告", "当前图像没有关联的文件路径")

    def remove_from_stitching(self):
        """从拼接队列中移除选中的图像"""
        selected_items = self.stitching_images_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "警告", "请先选择要移除的图像")
            return

        for item in selected_items:
            index = self.stitching_images_list.row(item)
            index = self.stitching_images_list.row(item)
            self.stitching_images_list.takeItem(index)
            if 0 <= index < len(self.images_to_stitch):
                self.images_to_stitch.pop(index)

        self.statusBar().showMessage(f"已从拼接队列移除 {len(selected_items)} 个图像")

    def stitch_images(self):
        """执行图像拼接"""
        if len(self.images_to_stitch) < 2:
            QMessageBox.warning(self, "警告", "请至少添加两张图像到拼接队列")
            return

        # 获取拼接方法
        method = self.stitching_method.currentText()

        # 禁用按钮并显示进度条
        self.stitch_images_btn.setEnabled(False)
        self.stitching_progress.show()
        self.stitching_progress.setValue(0)
        self.statusBar().showMessage("正在拼接图像...")

        # 创建并启动拼接线程
        self.stitching_thread = PanoramaStitchingThread(self.images_to_stitch, method)
        self.stitching_thread.stitching_complete.connect(self.on_stitching_complete)
        self.stitching_thread.progress_updated.connect(self.stitching_progress.setValue)
        self.stitching_thread.start()

    def on_stitching_complete(self, result):
        """图像拼接完成回调"""
        # 启用按钮并隐藏进度条
        self.stitch_images_btn.setEnabled(True)
        self.stitching_progress.hide()

        if result:
            self.current_image = result
            self.original_image = result.copy()
            self.detected_shapes = None
            self.shape_stats.clear()
            self.update_image_display()
            self.statusBar().showMessage("图像拼接完成")
        else:
            QMessageBox.critical(self, "错误", "图像拼接失败。可能是图像不匹配或内存不足。")
            self.statusBar().showMessage("图像拼接失败")

    def save_image(self):
        """保存图像"""
        if self.current_image:
            if self.current_image_path:
                try:
                    self.current_image.save(self.current_image_path)
                    self.statusBar().showMessage(f"已保存图像: {os.path.basename(self.current_image_path)}")
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"保存图像失败: {str(e)}")
                    self.statusBar().showMessage("保存图像失败")
            else:
                self.save_image_as()

    def save_image_as(self):
        """另存为图像"""
        if self.current_image:
            options = QFileDialog.Options()
            file_name, _ = QFileDialog.getSaveFileName(
                self, "保存图像", "",
                "图像文件 (*.png *.jpg *.jpeg *.bmp *.gif);;所有文件 (*)",
                options=options
            )

            if file_name:
                try:
                    # 如果有检测到的形状，保存带标注的图像
                    if self.detected_shapes:
                        image_to_save = self.draw_detected_shapes(self.current_image)
                        image_to_save.save(file_name)
                    else:
                        self.current_image.save(file_name)

                    self.current_image_path = file_name
                    self.statusBar().showMessage(f"已保存图像: {os.path.basename(file_name)}")
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"保存图像失败: {str(e)}")
                    self.statusBar().showMessage("保存图像失败")

    def open_video_file(self):
        """打开视频文件并播放"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择视频文件", "",
            "视频文件 (*.mp4 *.avi *.mkv *.flv);;所有文件 (*)"
        )
        if file_path:
            self.video_player.open_video(file_path)
            self.statusBar().showMessage(f"已加载视频: {os.path.basename(file_path)}")


if __name__ == "__main__":
    # 确保中文显示正常
    import matplotlib

    matplotlib.use('Agg')

    app = QApplication(sys.argv)
    # 设置应用样式
    app.setStyle('Fusion')
    window = ImageProcessor()
    window.show()
    sys.exit(app.exec_())